package player;

import game.DAO;
import game.SuperGame;
import graphisme.ChatGrapicalnterface;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class Player extends Thread implements Runnable {

	/**
	 * 
	 */
	Map<String, Integer> adrOpoppent = new HashMap<String, Integer>();
	DatagramSocket serverChatSocket = null;
	ChatGrapicalnterface windowChat = new ChatGrapicalnterface(this);
	String udpServerAddress = "";
	int udpServerPort;
	Socket socket = null;
	Socket tmpSocket = null;
	InputStream in;
	OutputStream out;
	BufferedReader bufIn = null;
	BufferedWriter bufOut = null;
	String currentMsg = "";
	JFrame frame = new JFrame("Information");
	String pseudo = "";
	SuperGame board = null;
	int score = 0;

	public Player() {

	}

	public Player(Socket socket) throws IOException {
		this.in = socket.getInputStream();
		this.bufIn = new BufferedReader(new InputStreamReader(in));
		this.out = socket.getOutputStream();
		this.bufOut = new BufferedWriter(new OutputStreamWriter(out));
	}

	public Player(String pseudo, Socket socket, String udpServerAdresse,
			int udpServerPort) throws IOException {

		this.udpServerAddress = udpServerAdresse;
		this.udpServerPort = udpServerPort;
		this.pseudo = pseudo;
		this.out = socket.getOutputStream();
		this.bufOut = new BufferedWriter(new OutputStreamWriter(out));
	}

	public Player(String pseudo, String gameToPlay) {

		// create connection socket
		try {
			// connect to the server
			socket = new Socket("localhost", 8888);
			this.udpServerPort = findFreePort();
			// UDP communication part
			serverChatSocket = new DatagramSocket(new InetSocketAddress(
					"localhost", udpServerPort));
			this.udpServerAddress = serverChatSocket.getLocalAddress()
					.toString();

			// create readers and writers messages
			this.in = socket.getInputStream();
			this.bufIn = new BufferedReader(new InputStreamReader(in));
			this.out = socket.getOutputStream();
			this.bufOut = new BufferedWriter(new OutputStreamWriter(out));

			// create current game object
			this.board = new DAO().getTypeOfGame(gameToPlay, this);

			// send pseudo and game to the server
			this.pseudo = pseudo;
			sendMsg(pseudo + "_" + gameToPlay + "_" + udpServerAddress + "_"
					+ udpServerPort);

			// send player object to sever
		} catch (IOException e1) {
			System.out
					.println("An error has been occured while connecting to the server socket");
			e1.printStackTrace();
		}
	}

	public void run() {
		// wait for a message reception
		while (true) {

			String msg;
			try {
				msg = bufIn.readLine();
				if (!msg.equals("")) {
					// wait for a player
					if (msg.equals("waitOtherPlayer")) {
						// show a popup
						JOptionPane.showMessageDialog(frame,
								"Waiting for an other player",
								"keep calm and wait noob :)",
								JOptionPane.PLAIN_MESSAGE);

					}
					// missing player found
					else if (msg.equals("opponentFound")) {
						JOptionPane
								.showMessageDialog(
										frame,
										"Your opponent has been found, are you happy now ?",
										"Enjoy it !!!!!!!!",
										JOptionPane.PLAIN_MESSAGE);

					}
					// connect to the thread
					else if (msg.contains("-ip")) {
						socket = new Socket("localhost", Integer.parseInt(msg
								.substring(0, msg.indexOf("-"))));
						// create readers and writers
						this.in = socket.getInputStream();
						this.out = socket.getOutputStream();
						this.bufIn = new BufferedReader(new InputStreamReader(
								in));
						this.bufOut = new BufferedWriter(
								new OutputStreamWriter(out));
						board.displayBoard(socket);
					}
					// if receive other players' address
					else if (msg.contains("_udpAdr")) {
						String[] tmpMessage = msg.split("_");
						adrOpoppent.put(tmpMessage[0],
								Integer.parseInt(tmpMessage[1]));
						// if receive every players' udp
						if (adrOpoppent.size() == board.getNbJoueur() - 1) {
							windowChat.createFrame();
							// launch listening thread for the chat
							windowChat.setAdrOpoppent(adrOpoppent);

							new Thread(new ThreadListenChat(serverChatSocket,
									windowChat, this)).start();

							// display chat window
							windowChat.setVisible(true);

						}

					}
					// if there another message -> game message
					else {
						// update game board
						System.out.println("on recoit le message Player : "+msg);
						board.refreshBoard(msg);
					}
					msg = "";

				}
			} catch (IOException e) {
				System.out.println("Problem de connection");
				e.printStackTrace();
			}

		}

	}

	public Socket getTmpSocket() {
		return this.tmpSocket;
	}

	// send message to server
	public void sendMsg(String msg) {
		try {
			this.bufOut.write(msg);
			this.bufOut.newLine();
			this.bufOut.flush();
		} catch (IOException e) {
			System.out
					.println("An error has been occured while sending the message to the server");
			e.printStackTrace();
		}
	}

	public void setBufOut(int port) throws IOException {
		InetSocketAddress serverAddr = new InetSocketAddress("localhost", port);
		socket.bind(serverAddr);
		this.out = socket.getOutputStream();
		this.bufOut = new BufferedWriter(new OutputStreamWriter(this.out));
	}

	public void setBufIn(Socket socket) throws IOException {
		this.in = socket.getInputStream();
		this.bufIn = new BufferedReader(new InputStreamReader(in));
	}

	public void setBufOut(Socket socket) throws IOException {
		this.tmpSocket = socket;
		this.out = socket.getOutputStream();
		this.bufOut = new BufferedWriter(new OutputStreamWriter(out));
	}

	public BufferedWriter getBufOut() {
		return this.bufOut;
	}

	public void setPseudo(String pseudo) {
		this.pseudo = pseudo;

	}

	public void setCurrentMsg(String s) {
		this.currentMsg = s;
	}

	public String getCurrentMsg() {
		return this.currentMsg;
	}

	public String getPseudo() {
		return this.pseudo;
	}

	public Socket getSocket() {
		return this.socket;
	}

	public int getScore() {
		return this.score;
	}

	public void setScore(int x) {
		this.score = x;
	}

	public String getUdpServerAddress() {
		return this.udpServerAddress;
	}

	public int getUdpServerPort() {
		return this.udpServerPort;
	}

	public int findFreePort() {
		for (int i = 7000; i <= 9999; i++) {
			if (available(i)) {
				return i;
			}
		}
		throw new RuntimeException("Could not find an available port between "
				+ 7000 + " and " + 9000);
	}

	private static boolean available(final int port) {
		ServerSocket serverSocket = null;
		DatagramSocket dataSocket = null;
		try {
			serverSocket = new ServerSocket(port);
			serverSocket.setReuseAddress(true);
			dataSocket = new DatagramSocket(port);
			dataSocket.setReuseAddress(true);
			return true;
		} catch (final IOException e) {
			return false;
		} finally {
			if (dataSocket != null) {
				dataSocket.close();
			}
			if (serverSocket != null) {
				try {
					serverSocket.close();
				} catch (final IOException e) {
					// can never happen
				}
			}
		}
	}
}